/// <license>
/// Copyright (c) 2002-2008, DotNetNuke Corporation
/// All rights reserved
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
/// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
/// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
/// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
/// of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
/// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
/// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
/// DEALINGS IN THE SOFTWARE.
/// </license>

using System;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

using DotNetNuke.Common;
using Globals = DotNetNuke.Common.Globals;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Modules.Actions;
using DotNetNuke.Security;
using DotNetNuke.UI.Utilities;
using DotNetNuke.UI.WebControls;
using DotNetNuke.ModuleToolkit.Framework;

namespace DotNetNuke.ModuleToolkit.Modules
{
    public abstract class AdvancedEditModuleBase : 
        AdvancedModuleBase, 
        IActionable
    {

        #region Private Members

        private string baseKey = "Item";
        private bool canEdit = Null.NullBoolean;
        private bool canView = true;
        private PropertyEditorControl editor = null;
        private CustomValidator validator = null;
        private object entity = null;
        private string keyField = "ItemID";
        private string placeHolderControlID = "EditorPlaceHolder";
        private bool returnOnCreate = true;
        private bool showDelete = true;
        private bool showSave = true;

#endregion

        #region Protected Properties

        /// <summary>
        /// BaseKey is the root name for all the Message Keys
        /// </summary>
        protected string BaseKey
        {
            get { return baseKey; }
            set { baseKey = value; }
        }

        /// <summary>
        /// CanEdit determines whether the current user has Edit Rights to this control
        /// </summary>
        protected bool CanEdit
        {
            get { return canEdit; }
            set { canEdit = value; }
        }

        /// <summary>
        /// CanView determines whether the current user has View Rights to this control
        /// </summary>
        protected bool CanView
        {
            get { return canView; }
            set { canView = value; }
        }

        /// <summary>
        /// ControlKey is the key for the current control (ctl=xx)
        /// </summary>
        protected string ControlKey
        {
            get
            {
                string controlKey = Null.NullString;
                if (Request.QueryString["ctl"] != null)
                    controlKey = Request.QueryString["ctl"];
                return controlKey;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        protected PropertyEditorMode PropertyEditMode
        {
            get 
            {
                EnsureChildControls();
                return Editor.EditMode; 
            }
            set 
            {
                EnsureChildControls();
                Editor.EditMode = value;
            }
        }

        /// <summary>
        /// Editor is the Property Editor Control that is used to edit the Entity
        /// </summary>
        protected PropertyEditorControl Editor
        {
            get { return editor; }
            set { editor = value; }
        }

        /// <summary>
        /// Entity is the object that is managed by ths control
        /// </summary>
        protected object Entity
        {
            get 
            {
                if (entity == null)
                {
                    if (IsAdd)
                    {
                        //Create new Entity
                        entity = CreateEntity();
                    }
                    else
                    {
                        //Get Existing Entity
                        entity = GetEntity(KeyValue);
                    }
                }
                return entity;
            }
        }

        /// <summary>
        /// IsAdd determines whether the control is in "Add" or "Edit" mode
        /// </summary>
        protected bool IsAdd
        {
            get { return (KeyValue == Null.NullInteger); }
        }

        /// <summary>
        /// KeyField identifies the Name of the Key Field use in the Name Value Pair in the QueryString 
        /// (ie ItemID=1  - ItemID is the keyfield)
        /// </summary>
        protected string KeyField
        {
            get { return keyField; }
            set { keyField = value; }
        }

        /// <summary>
        /// KeyValue is the Value of the KeyField Name-Value Pair in the Querystring
        /// </summary>
        protected int KeyValue
        {
            get
            {
                int keyValue = Null.NullInteger;
                if (Request.QueryString[KeyField] != null)
                    keyValue = Int32.Parse(Request.QueryString[KeyField]);
                return keyValue;
            }
        }

        /// <summary>
        /// PlaceHolderControlID is the ID of the placeholder control used to "inject" the Editor into the
        /// User Control
        /// </summary>
        protected string PlaceHolderControlID
        {
            get { return placeHolderControlID; }
            set { placeHolderControlID = value; }
        }

        /// <summary>
        /// ReturnOnCreate is a flag that determines the behaviour of the control when a new entity is created.
        /// If set to true - the user will be redirected to the calling page as determined by the ReturnUrl property.
        /// If set to false - the page will be refreshed.
        /// </summary>
        protected bool ReturnOnCreate
        {
            get { return returnOnCreate; }
            set { returnOnCreate = value; }
        }

        public bool ShowDelete
        {
            get { return showDelete; }
            set { showDelete = value; }
        }

        public bool ShowSave
        {
            get { return showSave; }
            set { showSave = value; }
        }


        #endregion

        #region Private Methods

        /// <summary>
        /// AddEntityInternal creates the current Entity
        /// </summary>
        private void AddEntityInternal()
        {
            string returnUrl;

            if (Validate())
            {
                try
                {
                    //Add New Entity
                    int entityID = AddEntity(Editor.DataSource);

                    if (ReturnOnCreate)
                    {
                        MessageKey = BaseKey + "AddedSuccess";
                        returnUrl = ReturnURL;
                    }
                    else
                        if (String.IsNullOrEmpty(Scope))
                            returnUrl = EditUrl(KeyField, entityID.ToString(), ControlKey, "Message=" + BaseKey + "AddedSuccess");
                        else
                            returnUrl = EditUrl(KeyField, entityID.ToString(), ControlKey, "Scope=" + Scope + "&Message=" + BaseKey + "AddedSuccess");
                }
                catch
                {
                    MessageKey = BaseKey + "AddedError";
                    returnUrl = ReturnURL;
                }

                Response.Redirect(returnUrl, true);
            }
        }

        /// <summary>
        /// DeleteEntityInternal deletes the current entity.
        /// </summary>
        private void DeleteEntityInternal()
        {
            try
            {
                DeleteEntity(Entity);

                MessageKey = BaseKey + "DeletedSuccess";
            }
            catch
            {
                MessageKey = BaseKey + "DeletedError";
            }

            //Return
            Response.Redirect(ReturnURL, true);
        }

        /// <summary>
        /// UpdateEntityInternal updates the current Entity
        /// </summary>
        private void UpdateEntityInternal()
        {
            if (Validate())
            {
                if (Editor.IsDirty)
                {
                    try
                    {
                        //Update Entity
                        UpdateEntity(Editor.DataSource);

                        MessageKey = BaseKey + "UpdateSuccess";
                    }
                    catch
                    {
                        MessageKey = BaseKey + "UpdateError";
                    }
                }
                else
                {
                    MessageKey = BaseKey + "NotUpdatedWarning";
                }

                Response.Redirect(ReturnURL, true);
            }
        }

        /// <summary>
        /// Validate validates the Entity being edited.
        /// </summary>
        private bool Validate()
        {
            bool isValid = Editor.IsValid;
            string errorMessage = Null.NullString;
            IValidatable entity = Editor.DataSource as IValidatable;
            if (entity != null)
            {
                isValid = entity.IsValid;
                errorMessage = entity.ValidationMessage;
            }

            if (!isValid)
            {
                validator.IsValid = false;
                validator.ErrorMessage = LocalizeString(errorMessage);
            }

            return isValid;

        }

        #endregion

        #region Protected Methods

        /// <summary>
        /// AddEntity creates the current Entity in the DataStore
        /// </summary>
        /// <remarks>This method must be overridden in the sub-class</remarks>
        /// <param name="entity">The entity to create</param>
        protected abstract int AddEntity(object entity);

        /// <summary>
        /// CreateChildControls injects the Editor into the Controls collection
        /// </summary>
        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            editor = new PropertyEditorControl();
            editor.ID = "Editor";
            editor.SortMode = PropertySortType.SortOrderAttribute;
            editor.EditControlStyle.CssClass = "NormalTextBox";
            editor.EditControlWidth = Unit.Pixel(400);
            editor.ErrorStyle.CssClass = "NormalRed";
            editor.GroupHeaderIncludeRule = true;
            editor.GroupHeaderStyle.CssClass = "Head";
            editor.HelpStyle.CssClass = "Help";
            editor.LabelStyle.CssClass = "SubHead";
            editor.LabelWidth = Unit.Pixel(200);
            editor.Width = Unit.Pixel(600);
            editor.LocalResourceFile = LocalResourceFile;

            validator = new CustomValidator();
            validator.ControlStyle.CssClass = "NormalRed";

            //Look for a PlaceHolder
            PlaceHolder placeHolder = this.FindControl(PlaceHolderControlID) as PlaceHolder;

            if (placeHolder != null)
            {
                placeHolder.Controls.Add(editor);
                placeHolder.Controls.Add(validator);
            }
            else
            {
                this.Controls.AddAt(0, editor);
                this.Controls.AddAt(1, validator);
            }
        }

        /// <summary>
        /// CreateEntity creates a new Entity in memory
        /// </summary>
        /// <remarks>This method must be overridden in the sub-class</remarks>
        protected abstract object CreateEntity();

        /// <summary>
        /// DeleteEntity deletes the current Entity in the DataStore
        /// </summary>
        /// <remarks>This method must be overridden in the sub-class</remarks>
        /// <param name="entity">The entity to delete</param>
        protected abstract void DeleteEntity(object entity);

        /// <summary>
        /// GetEntity retrieves an entity from the DataStore
        /// </summary>
        /// <param name="keyValue">The key that identifies the Entity</param>
        /// <returns>The entity</returns>
        protected abstract object GetEntity(int keyValue);

        /// <summary>
        /// ModueAction processes other Module Actions not handled directly by the base class
        /// </summary>
        /// <param name="action">The action to process</param>
        protected virtual void ModuleAction(string action)
        {
        }

        /// <summary>
        /// OnInit runs when the control is initialized by the ASP.NET Page framework
        /// </summary>
        /// <param name="e">An EventArgs object</param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            if ((PropertyEditMode == PropertyEditorMode.View && CanView) || (PropertyEditMode == PropertyEditorMode.Edit && CanEdit))
            {
                if (PropertyEditMode == PropertyEditorMode.View)
                {
                    ModuleConfiguration.ModuleTitle = LocalizeString("View");
                }
                else
                    if (IsAdd)
                        ModuleConfiguration.ModuleTitle = LocalizeString("Add");
                    else
                        ModuleConfiguration.ModuleTitle = LocalizeString("Edit");
            }
            else
            {
                //Security breach
                Response.Redirect(Globals.AccessDeniedURL(LocalizeString("ModuleAccess.Error")), true);
            }


        }

        /// <summary>
        /// OnLoad runs when the control is loaded by the ASP.NET Page framework
        /// </summary>
        /// <param name="e">An EventArgs object</param>
        protected override void OnLoad(EventArgs e)
        {
            //Add an Action Event Handler to the Skin
            AddActionHandler(new ActionEventHandler(ModuleAction_Click));

            //Ensure Child Controls are Created
            this.EnsureChildControls();

            base.OnLoad(e);

            DataBind();
        }

        /// <summary>
        /// UpdateEntity updates the current Entity in the DataStore
        /// </summary>
        /// <remarks>This method must be overridden in the sub-class</remarks>
        /// <param name="entity">The entity to update</param>
        protected abstract void UpdateEntity(object entity);

        #endregion

        #region Public Methods

        public override void DataBind()
        {
            //Data Bind the Editor
            Editor.LocalResourceFile = this.LocalResourceFile;
            Editor.DataSource = Entity;
            Editor.DataBind();

            base.DataBind();
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// ModuleAction_Click runs when a Module Action is clicked
        /// </summary>
        /// <param name="sender">The object that triggered the event</param>
        /// <param name="e">An ActionEventArgs object</param>
        protected void ModuleAction_Click(object sender, ActionEventArgs e)
        {
            string action = e.Action.CommandArgument;
            switch (action)
            {
                case "Delete":
                    DeleteEntityInternal();
                    break;
                case "Save":
                    if (IsAdd)
                        AddEntityInternal();
                    else
                        UpdateEntityInternal();
                    break;
                default:
                    ModuleAction(action);
                    break;
            }
        }

        #endregion

        #region IActionable Members

        /// <summary>
        /// ModuleActions is the IActionable property that contains the module actions
        /// </summary>
        /// <remarks>The base Edit Class automatically adds the Add/Delete/Save/Return Actions.</remarks>
        public virtual ModuleActionCollection ModuleActions
        {
            get
            {
                ModuleActionCollection Actions = new ModuleActionCollection();
                if (PropertyEditMode == PropertyEditorMode.Edit)
                {
                    if (CanEdit && !IsAdd && ShowDelete)
                    {
                        Actions.Add(GetNextActionID(), LocalizeString("Delete"), ModuleActionType.AddContent, "Delete", "delete.gif", "", "confirm('" + ClientAPI.GetSafeJSString(LocalizeString("DeleteItem")) + "')", true, SecurityAccessLevel.View, true, false);
                    }
                    if (ShowSave)
                    {
                        if (IsAdd)
                            Actions.Add(GetNextActionID(), LocalizeString("Create"), ModuleActionType.AddContent, "Save", "save.gif", "", false, SecurityAccessLevel.View, true, false);
                        else
                            Actions.Add(GetNextActionID(), LocalizeString("Save"), ModuleActionType.AddContent, "Save", "save.gif", "", false, SecurityAccessLevel.View, true, false);
                    }
                }
                Actions.Add(GetNextActionID(), LocalizeString("Return"), ModuleActionType.AddContent, "", "lt.gif", ReturnURL, false, SecurityAccessLevel.View, true, false);
                return Actions;
            }
        }

        #endregion

    }
}
